package com.ppch.zerocodegenerator.exception;


import cn.hutool.json.JSONUtil;
import com.ppch.zerocodegenerator.common.BaseResponse;
import com.ppch.zerocodegenerator.common.ResultUtils;
import dev.langchain4j.guardrail.InputGuardrailException;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.IOException;
import java.util.Map;

/**
 * Package:ppch.zerocodegenerator
 * ClassName:GlobalExceptionHandler
 *
 * @Author 泡泡茶壶
 * @Create 2024/12/13 17:34
 * @Version 1.0
 * Description:
 *  全局异常处理器
 */
@Hidden
//将类标记为全局异常处理器，捕获并处理所有控制器（Controller）中抛出的异常。
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理自定义异常
     */
    @ExceptionHandler(BusinessException.class)
    public BaseResponse<?> businessExceptionHandler(BusinessException e) {
        log.error("BusinessException", e);
        // 尝试处理 SSE 请求
        if (handleSseError(e.getCode(), e.getMessage())) {
            return null;
        }
        // 对于普通请求，返回标准 JSON 响应
        return ResultUtils.error(e.getCode(), e.getMessage());
    }

    /**
     * 处理运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
        log.error("RuntimeException", e);
        // 尝试处理 SSE 请求
        if (handleSseError(ErrorCode.SYSTEM_ERROR.getCode(), "系统错误")) {
            return null;
        }
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
    }

    /**
     * 捕获非法参数异常，本项目主要是针对请求参数过长异常（AI对话接口，用户发送的Prompt过长）
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public BaseResponse<?> illegalArgumentExceptionHandler(IllegalArgumentException e) {
        log.error("IllegalArgumentException", e);
        // 尝试处理 SSE 请求
        if (handleSseError(ErrorCode.REQUEST_PARAMETER_TOO_LONG_ERROR.getCode(), "输入内容过长，不要超过 1000 字")) {
            return null;
        }
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
    }

    /**
     * 处理输入护轨异常 InputGuardrailException
     */
    @ExceptionHandler(InputGuardrailException.class)
    public BaseResponse<?> businessExceptionHandler(InputGuardrailException e) {
        log.error("InputGuardrailException", e);
        // 尝试处理 SSE 请求
        // 只截取异常信息中的中文提示信息
        String exceptionMessage = getTextAfterColon(e.getMessage());
        boolean b = handleSseError(ErrorCode.ILLEGAL_INPUT.getCode(), exceptionMessage);
        if (b) {
            return null;
        }else {
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
        }
    }

    /**
     * 处理SSE请求的错误响应
     *
     * @param errorCode 错误码
     * @param errorMessage 错误信息
     * @return true表示是SSE请求并已处理，false表示不是SSE请求
     */
    private boolean handleSseError(int errorCode, String errorMessage) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return false;
        }
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        // 判断是否是SSE请求（通过Accept头或URL路径）
        String accept = request.getHeader("Accept");
        String uri = request.getRequestURI();
        if ((accept != null && accept.contains("text/event-stream")) ||
                uri.contains("/chat/gen/code")) {
            try {
                // 设置SSE响应头
                response.setContentType("text/event-stream");
                response.setCharacterEncoding("UTF-8");
                response.setHeader("Cache-Control", "no-cache");
                response.setHeader("Connection", "keep-alive");
                // 构造错误消息的SSE格式
                Map<String, Object> errorData = Map.of(
                        "error", true,
                        "code", errorCode,
                        "message", errorMessage
                );
                String errorJson = JSONUtil.toJsonStr(errorData);
                // 构造并发送业务错误事件（避免与标准error事件冲突）
                String sseData = "event: business-error\ndata: " + errorJson + "\n\n";
                response.getWriter().write(sseData);
                response.getWriter().flush();
                // 发送结束事件
                response.getWriter().write("event: done\ndata: {}\n\n");
                response.getWriter().flush();
                // 表示已处理SSE请求
                return true;
            } catch (IOException ioException) {
                log.error("Failed to write SSE error response", ioException);
                // 即使写入失败，也表示这是SSE请求
                return true;
            }
        }
        return false;
    }

    /**
     * 获取字符串中冒号后面的字符（只能处理字符串中只包含一个冒号的情况）
     * 例如：The guardrail com.ppch.zerocodegenerator.ai.guardrail.PromptSafetyInputGuardrail failed with this message: 输入包含不当内容，请修改后重试
     * 最后只截取：“输入包含不当内容，请修改后重试”
     * @param input 字符串
     * @return 截取后的字符串
     */
    public static String getTextAfterColon(String input) {
        // 检查输入是否为空
        if (input == null) {
            return "";
        }

        // 查找冒号的位置
        int colonIndex = input.indexOf(":");
        if (colonIndex == -1) {
            // 没有找到冒号，返回空字符串
            return "";
        }

        // 提取冒号后面的内容
        return input.substring(colonIndex + 1);
    }
}

